#include "timer.h"
#include "cmsis_os2.h"
#include "log/logger.h"

static void __TimerCallback(void *argument)
{
    Timer *timer = static_cast<Timer*>(argument);

    if(timer)
    {
        timer->CallImpl();
        //只负责stop，不负责delete，调用方自己delete
        if(timer->GetTimerType() == Timer::TimerType::OneShot)
        {
            timer->Stop();
        }
    }
}

Timer::Timer()
{
}

Timer::Timer(int interval, Timer::TimerType type)
{
    m_interval = interval;
    m_timerType = type;
}

Timer::~Timer()
{
    DeleteTimer();
}

void Timer::SetInterval(int interval)
{
    m_interval = interval;
    //动态更改需要调用osTimerStart
    if(IsRunning())
        osTimerStart(m_timerHandle, m_interval);
}

int Timer::GetInterval()
{
    return m_interval;
}

void Timer::SetTimerType(Timer::TimerType type)
{
    m_timerType = type;
}

Timer::TimerType Timer::GetTimerType()
{
    return m_timerType;
}

void Timer::SetElapsed(std::function<void(Timer &timer)> func)
{
    m_func = func;
}

void Timer::Start()
{
    if(IsRunning())
        return;

    if(m_timerHandle == nullptr)
    {
        CreateTimer();
    }

    auto st = osTimerStart(m_timerHandle, m_interval);
    m_isRunning = st == osStatus_t::osOK;
    if(!m_isRunning)
    {
        LogDebug()<<"start timer failed.";
    }
}

void Timer::Restart()
{
    Stop();
    Start();
}

void Timer::Stop()
{
    if(m_timerHandle == nullptr)
        return;
    if(IsRunning() == false)
        return;
    osTimerStop(m_timerHandle);
    m_isRunning = false;
}

bool Timer::IsRunning()
{
    return m_timerHandle != nullptr && m_isRunning;
}

void Timer::SingleShot(int ms, const std::function<void(void)> &&func)
{
    Timer *timer = new Timer(ms, Timer::TimerType::OneShot); 

    timer->SetElapsed([=](auto &sender){
        func();
        timer->Stop();
        delete timer;
    });
    timer->Start();
}

void Timer::CallImpl()
{
    if(m_func)
    {
        m_func(*this);
    }
}

void Timer::CreateTimer()
{
    osTimerAttr_t attr = {0};
    osTimerType_t type;
	
    attr.name = "timer";
    type = (m_timerType == TimerType::OneShot)? osTimerType_t::osTimerOnce : osTimerType_t::osTimerPeriodic;
    m_timerHandle = osTimerNew(__TimerCallback, type, this, &attr);
}

void Timer::DeleteTimer()
{
    if(m_timerHandle == nullptr)
        return;

    if(osTimerIsRunning(m_timerHandle))
    {
        osTimerStop(m_timerHandle);
    }

    osTimerDelete(m_timerHandle);
    m_timerHandle = nullptr;
}
